package com.example.leepong.Game;

import android.util.Log;

import com.example.leepong.Game.Engines.*;
import com.example.leepong.Game.Entities.*;

import com.example.leepong.Game.Presets.PlayerProfileStore;
import com.example.leepong.Game.Shapes.Coordinates;
import com.example.leepong.Game.Shapes.Rectangle;
import com.example.leepong.Game.Stage.StageConfiguration;
import com.example.leepong.Game.Utils.Stopwatch;
import com.example.leepong.Game.Interaction.*;

import com.example.leepong.Game.Events.*;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Created by Ichigo on 28/02/14.
 */
public class Engine {

    public Ball Ball;
    public Land Land;
    public Racket TopRacket;
    public Racket BottomRacket;

    public Score LeftScore;
    public Score RightScore;

    private CollisionDetector _collisionDetector;
    private TouchDetector _touchDetector;
    private int TOUCH_TOLERANCE = 40;
    private Rectangle _racketLTouchZone;

    public boolean IsRunning;

    public EventsBroadcaster EventsBroadcaster;
    private EventsAggregator _eventsAggregator;

    public Engine() {

        this.Ball = new Ball();
        this.TopRacket = new Racket();
        this.BottomRacket = new Racket();
        this._eventsAggregator = new EventsAggregator();
        this.EventsBroadcaster = new EventsBroadcaster(_eventsAggregator);
        _collisionDetector = new CollisionDetector(this, new CollisionManager(this));
        _touchDetector = new TouchDetector(this, new TouchManager(this));
    }

    public void Init(int width, int height, StageConfiguration stageConfig) {
        this.Land = new Land(new Rectangle(0, 0, width, height));

        this.TopRacket.Rect.Width = (int) (this.Land.Rect.Width * stageConfig.TopPlayerConfig.profile.WidthRatio);
        this.TopRacket.Rect.Height = (int) (this.Land.Rect.Height * stageConfig.TopPlayerConfig.profile.HeightRatio);

        this.BottomRacket.Rect.Width = (int) (this.Land.Rect.Width * PlayerProfileStore.ReferenceWidthRatio);
        this.BottomRacket.Rect.Height = (int) (this.Land.Rect.Height * PlayerProfileStore.ReferenceHeightRatio);

        this.TopRacket.Rect.Coord.Y = this.Land.Rect.Top;
        this.TopRacket.Rect.setCenterX(this.Land.Rect.CenterX);
        this.BottomRacket.Rect.Coord.Y = this.Land.Rect.Bottom - this.BottomRacket.Rect.Height;
        this.BottomRacket.Rect.setCenterX(this.Land.Rect.CenterX);

        this.Ball.Rect.Width = this.Land.Rect.Height / 11;
        this.Ball.Rect.Height = this.Ball.Rect.Width;
        this.Ball.Rect.setCenterX(this.Land.Rect.CenterX);
        this.Ball.Rect.setCenterY(this.Land.Rect.CenterY);

        Rectangle leftscoreRect = new Rectangle();
        leftscoreRect.Width = this.Land.Rect.Height / 4;
        leftscoreRect.Height = leftscoreRect.Width;
        leftscoreRect.Coord.X = this.Land.Rect.CenterX;
        leftscoreRect.Coord.Y = this.Land.Rect.Bottom * 0.4f;
        LeftScore = new Score(leftscoreRect);

        Rectangle rightScoreRect = new Rectangle();
        rightScoreRect.Width = leftscoreRect.Width;
        rightScoreRect.Height = leftscoreRect.Width;
        rightScoreRect.Coord.X = this.Land.Rect.CenterX;
        rightScoreRect.Coord.Y = this.Land.Rect.Bottom * 0.8f;
        RightScore = new Score(rightScoreRect);

//        PlayerProfile profile = new PlayerProfile();
//        profile.MoveSpeed = 0.5f;
//        profile.RecenterSpeed = 0.3f;
//        profile.Power = 0.4f;
//
//        profile.ShotSelection = new ArrayList<Shot>(
//                Arrays.asList(Shot.Reflect, Shot.Reflect, Shot.Cross, Shot.Cross, Shot.Counter, Shot.Long)
//        );

        this.TopRacket.Assign(new VirtualPlayer(this, stageConfig.TopPlayerConfig.profile));
        this.BottomRacket.Assign(new HumanPlayer(this));
        //this.BottomRacket.Assign(new VirtualPlayer(this, profile));

    }

    public void Calibrate(float ups) {
        this.Ups = ups;
        this.Ball.Angle = 40;
        this.Ball.DefaultMoveStep = this.Land.Rect.Height / (Ups * 1.5f);
        this.Ball.MoveStep = this.Ball.DefaultMoveStep;
        this.Ball.NormalizeSpeedRatio = 1.2f / Ups;
    }

    public float Ups;
    private long prev;
    private long _updateCounter;

    private Stopwatch _stopwatch = new Stopwatch();
    private long lastTime = 0;
    public long deltaTime = 0;

    public void Update() {
        traceBall();
        if (!IsRunning) {
            return;
        }

        deltaTime = _stopwatch.getElapsedMilliseconds() - lastTime;
        lastTime = _stopwatch.getElapsedMilliseconds();
        HandleUpdateCount();

        this.Ball.Update();
        _collisionDetector.Check();

        this.BottomRacket.Player.Update();
        this.TopRacket.Player.Update();
    }

    public int balln0;
    public int balln1;
    public int balln2;
    public int balln3;

    private void traceBall() {
        balln3 = balln2;
        balln2 = balln1;
        balln1 = balln0;
        balln0++;
    }

    private void HandleUpdateCount() {
        _updateCounter++;
        if (_updateCounter % 100 == 0) {
            long now = System.currentTimeMillis();
            long dif = (now - prev);


            double _currentFps = (int) (100 / (dif / 1000.0));
            Log.d("----", "ball fps" + _currentFps);
            Log.d("----", "deltaTime" + deltaTime);
            prev = now;
        }
    }

    public void PauseResume(boolean notify) {
        if (IsRunning) {
            Pause(notify);
        } else {
            Resume(notify);
        }
    }

    public void Pause(boolean notify) {
        _stopwatch.Pause();
        IsRunning = false;

        if (notify)
            _eventsAggregator.FireGamePaused();
    }

    public void Resume(boolean notify) {
        _stopwatch.Start();
        IsRunning = true;

        if (notify)
            _eventsAggregator.FireGameResumed();
    }

    public void TouchScroll(Coordinates newCoords, Coordinates oldCoords) {
        _touchDetector.NotifyScroll(newCoords, oldCoords);
    }

    public void TouchSingleTap(Coordinates coordinates) {
        _touchDetector.NotifyTap(coordinates);
    }
}

